using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;
using AppEventUtils;
using UnityEngine.UI;
using TMPro;
using System;
using System.Data;
using System.Linq;
using AppGameState;
using AppSoldierState;
using UnityEngine.Serialization;
using AppTableUtils;
using UnityEditor; // 需要引入才能操作资源保存


using UnityEngine.Networking;

using System.IO;
using Unity.VisualScripting;
using UnityEngine.PlayerLoop;

public class GameController : MonoBehaviour
{

    [Header("sale_effect的世界父级节点")] public Transform sale_effect_parent_trans;
    public int card_uid = 1;
    
    public static GameController instance;

    private void Awake()
    {
        if (instance != null)
            Destroy(this);
        instance = this;
    }
    
    [HideInInspector] public List<Vector3> positions_store = new List<Vector3>();
    [HideInInspector] public List<Vector3> positions_enemy = new List<Vector3>();
    [HideInInspector] public List<Vector3> positions_player = new List<Vector3>();

    public int max_len_store = 5;
    public int max_len_enemy = 7;
    public int max_len_player = 7;
    public int max_len_cards_in_hand = 10;
    
    public GameObject card_prefab;
    public string card_obj_name = $"card_prefab";
    
    [HideInInspector] public float card_height;
    [HideInInspector] public float card_width;
    
    [HideInInspector] public const float _default_card_spacing = -99;
    [Header("卡牌间隔")] public float card_spacing = _default_card_spacing;
    
    // 角色 -> 是否在手牌中 -> 卡牌列表, 例如: role_cards_dc[RoleTypeEnum.player][true] -> player角色 手牌中的 卡牌列表
    [HideInInspector] public Dictionary<RoleTypeEnum, Dictionary<bool, List<GameObject>>> role_cards_dc = new Dictionary<RoleTypeEnum, Dictionary<bool, List<GameObject>>> ();
    [Header("卡牌最大数量")] public Dictionary<RoleTypeEnum, Dictionary<bool, int>> role_cards_max_number_dc = new Dictionary<RoleTypeEnum, Dictionary<bool, int>> ();

    [HideInInspector] public List<GameObject> frozen_store_cards = new List<GameObject>();
    [HideInInspector] public List<GameObject> enemy_soldiers => role_cards_dc[RoleTypeEnum.enemy][false];
    [HideInInspector] public List<GameObject> player_soldiers => role_cards_dc[RoleTypeEnum.player][false];
    [HideInInspector] public List<GameObject> store_soldiers => role_cards_dc[RoleTypeEnum.store_owner][false];
    
    [HideInInspector] public List<GameObject> enemy_hands => role_cards_dc[RoleTypeEnum.enemy][true];
    [HideInInspector] public List<GameObject> player_hands => role_cards_dc[RoleTypeEnum.player][true];

    // [HideInInspector] public List<GameObject> player_soldiers = new List<GameObject>();
    // [HideInInspector] public List<GameObject> store_soldiers = new List<GameObject>();
    
    [Header("商店场地")]
    public GameObject store_place;
    [Header("战斗场地")]
    public GameObject battle_place;
    
    [Header("对手手牌位置")]
    public GameObject enemy_hand_place;
    [Header("玩家手牌位置")]
    public GameObject player_hand_place;

    public Animator game_animator;

    public List<GameObject> get_frozen_cards()
    {
        frozen_store_cards = role_cards_dc[RoleTypeEnum.store_owner][false].FindAll(card => card.GetComponent<CardController>().is_frozen);
        return frozen_store_cards;
    }
    public List<GameObject> get_activated_cards(RoleTypeEnum role_type, bool is_in_hand = false, bool is_activated = true)
    {
        var target_cards = role_cards_dc[role_type][is_in_hand].FindAll(card => card.activeInHierarchy == is_activated);
        return target_cards;
    }

    // 将store_owner的卡牌`is_frozen`全部设置为true
    public void btn_freeze_store_cards(bool cancel = false)
    {
        BdPackage.BdUtils.log("--- btn_freeze_store_cards");
        // 获取 store_owner 所有卡牌
        var storeCards = role_cards_dc[RoleTypeEnum.store_owner][false];

        var frozen_cards = get_frozen_cards();

        if (frozen_cards.Count == store_soldiers.Count)
        {
            cancel = true;
        }
        else
        {
            cancel = false;
        }
    
        // 遍历并设置 is_frozen 为 true
        foreach (var card in storeCards)
        {
            var cardController = card.GetComponent<CardController>();
            if (cardController != null)
            {
                cardController.is_frozen = !cancel;
                // cardController.is_frozen = cancel ? false : !cardController.is_frozen;
            }
        }
    }

    public int current_store_level
    {
        get
        {
            return BaseInfoManager.instance.current_store_level;
        }
        set
        {
            BaseInfoManager.instance.current_store_level = value;
        }
    }

    public GameObject store_level_stars;
    public GameObject level_up_effect;
    public GameObject refresh_level_info_effect;

    public void btn_level_up()
    {
        if (current_store_level >= BaseInfoManager.MAX_STORE_LEVEN)
            return;
        
        level_up_effect.SetActive(true);
        float t = 2f;  // [延迟/等待/休眠/timeout]t秒后执行
        DOTween.To(() => t, (x) => t = x, 0, t).OnComplete(
            () =>
            {
                core_level_up();
                refresh_level_info_effect.SetActive(true);
            }
        );

    }
    public void core_level_up()
    {
        if (current_store_level >= BaseInfoManager.MAX_STORE_LEVEN)
            return;

        current_store_level++;
        for (int i = 0; i < store_level_stars.transform.childCount; i++)
        {
            var obj_i = store_level_stars.transform.GetChild(i).gameObject;
            if (obj_i.name == $"star_{current_store_level}")
            {
                obj_i.SetActive(true);
            }
            else
            {
                obj_i.SetActive(false);
            }
        }
    }
    
    public Vector3 change_position_x(Vector3 position, float x)
    {
        return new Vector3(x, position.y, position.z);
    }

    public void set_soldier_ordering_text(GameObject soldier_obj, int ordering)
    {
        var text_comp = BdTools.get_component_in_obj_self_or_children<TextMeshPro>(soldier_obj);
        BdPackage.BdUtils.assert(text_comp != null, "text_comp is null");
        text_comp.text = ordering.ToString();
    }

    public GameStateEnum current_game_state = GameStateEnum.Store;

    public bool move_card_to_selected_place(Vector3 mouse_position, CardController card_comp, RoleTypeEnum target_role = RoleTypeEnum.None,
        bool is_in_hand = false, bool fail_to_recycle = false)
    {
        int ordering = get_ordering_of_position(position: mouse_position, role_type: target_role, is_in_hand: is_in_hand);
        // BdPackage.BdUtils.log($"~~~ ordering: {ordering}, old_ordering: {card_comp.parameter.ordering}");
        if (ordering == -1)
        {
            return false;
        }
        // BdPackage.BdUtils.log($"--- ordering: {ordering}, old_ordering: {card_comp.parameter.ordering}");
        return move_card_to_selected_place(card_comp: card_comp, target_role: target_role, is_in_hand: is_in_hand, ordering: ordering, fail_to_recycle: fail_to_recycle);
    }
    
    [HideInInspector] public Vector3 _out_position = new Vector3(-9, -4, 0); 
    public bool move_card_to_selected_place(CardController card_comp, RoleTypeEnum target_role = RoleTypeEnum.None,
        bool is_in_hand = false, int ordering = -1, bool fail_to_recycle = false)
    {
        if (target_role == RoleTypeEnum.None)
        {
            target_role = card_comp.parameter.belong_to;
            is_in_hand = card_comp.parameter.is_in_hand;
        }

        if (ordering == -1)
        {
            ordering = card_comp.parameter.ordering;
        }
        
        BdPackage.BdUtils.assert(target_role != RoleTypeEnum.None);
        
        // BdPackage.BdUtils.log($"=== move_card_to_selected_place, card_comp: {card_comp}");
        
        return move_card_to_selected_place(
                card_obj: card_comp.gameObject,
                ordering: ordering,
                target_role: target_role,
                is_in_hand: is_in_hand,
                fail_to_recycle: fail_to_recycle
            );
        // return move_card_to_selected_place(card_obj: card_comp.gameObject,
        //     ordering: ordering, target_role: target_role, is_in_hand: is_in_hand, fail_to_recycle: fail_to_recycle);
    }

    public bool remove_card_from_selected_place(CardController card_comp, bool recycle_card = true)
    {
        if (card_comp.parameter.belong_to == RoleTypeEnum.None)
        {
            recycle_one_card(card_comp);
            return false;
        }

        var role_type = card_comp.parameter.belong_to;
        
        var is_in_hand = card_comp.parameter.is_in_hand;
        
        var (y, max_length, card_ls) = get_info_by_card_obj(role_type, is_in_hand);
        var card_obj = card_comp.gameObject;

        // BdPackage.BdUtils.log($"--- remove_card_from_selected_place --- role_type: {role_type}, is_in_hand: {is_in_hand} --- ordering: {card_comp.parameter.ordering}");
        
        int old_count = card_ls.Count;

        if (!card_ls.Contains(card_obj))
        {
            BdPackage.BdUtils.log($"*** card_ls 为啥不包含 card_obj[{card_obj.name}]?");
            return false;
        }
        // BdPackage.BdUtils.assert(card_ls.Contains(card_obj));
        card_ls.Remove(card_obj);

        if (recycle_card)
        {
            recycle_one_card(card_obj);
        }

        // BdPackage.BdUtils.log($"=== on remove_card_from_selected_place! old_count: {old_count}, new_count: {card_ls.Count}");

        var ordering = card_comp.parameter.ordering;
        
        var center_ls = get_center_ls(card_ls.Count);
        center_ls.Sort();
        
        refresh_place_cards_order(card_ls, y, ordering, card_comp);
        return true;
    }

    public void refresh_place_cards_order(RoleTypeEnum role_type, bool is_in_hand = false)
    {
        var (y, max_length, card_ls) = get_info_by_card_obj(role_type, is_in_hand);
        refresh_place_cards_order(card_ls, y, max_length);
    }
    
    private void refresh_place_cards_order(
        List<GameObject> card_ls, float y, int ordering = -1,
        CardController soldier = null)
    {
        var center_ls = get_center_ls(card_ls.Count);
        center_ls.Sort();
        
        for (var i = 0; i < card_ls.Count; i++)
        {
            var player_soldier_i = card_ls[i];
            var player_soldier_comp_i = player_soldier_i.GetComponent<CardController>();
            BdPackage.BdUtils.assert(player_soldier_comp_i != null, $"--- i[{i}] --- player_soldier_comp_i from obj[{player_soldier_i.name}] is null");
        
            Vector3 new_position = new Vector3(center_ls[i], y, player_soldier_i.transform.position.z);
            var old_position = player_soldier_i.transform.position;

            if (player_soldier_comp_i.parameter.is_in_hand)
            {
                player_soldier_comp_i.btn_change_to_card_state();
            }
            else
            {
                player_soldier_comp_i.btn_change_to_soldier_state();    
            }
        
            if (i < ordering)
            {
                player_soldier_i.transform.DOMove(new_position, 0.2f);
            }
            else if (i == ordering && soldier?.gameObject == player_soldier_i)
            {
                // player_soldier_i.transform.position = Vector3.zero;
                old_position = player_soldier_i.transform.position;
                player_soldier_i.transform.DOMove(new_position, 0.2f);
            }
            else
            {
                player_soldier_comp_i.parameter.ordering = i;
                player_soldier_i.transform.DOMove(new_position, 0.2f);
                // set_soldier_ordering_text(player_soldier_i, i);
            }
        
            // old_position_ls.Add(old_position);
            // new_position_ls.Add(new_position);
        }
    }

    // private bool change_to_big_flag = false;
    
    [HideInInspector] public bool is_waiting_select_state = false;  // 用来判断是否等待选择状态
    public GameObject mask_canvas;

    [FormerlySerializedAs("selected_card")] [HideInInspector] public List<CardController> selected_cards;
    [HideInInspector] public int need_select_num = 1;
    [HideInInspector] public bool cancel_select = false;
    [HideInInspector] public bool end_select = false;

    public void btn_cancel_select()
    {
        cancel_select = true;
    }
    
    public void btn_end_select()
    {
        end_select = true;
    }

    [Header("确定选择按钮")] public GameObject select_confirm_btn;

    public bool is_confirmed = false;
    public void btn_confirm_selected()
    {
        is_confirmed = true;
        is_waiting_select_state = false;
    }
    
    public IEnumerator start_select_event(
        CardController card_comp,
        int select_num,
        RoleTypeEnum select_target_role,
        RoleTypeEnum old_belong_to,
        bool old_is_in_hand,
        int old_ordering,
        bool need_confirm = false)
    {
        cancel_select = false;
        end_select = false;
        need_select_num = select_num;
        is_waiting_select_state = true;
        
        selected_cards.Clear();

        yield return new WaitForSeconds(0.2f);  // 进入时还在排序中, 不等待的话容易z轴错误, 导致被mask遮盖
        
        // select_target_role = RoleTypeEnum.store_owner;
        if (select_target_role == RoleTypeEnum.player)
        {
            change_soldiers_to_waiting_select_state(card_comp.parameter.ordering, target_role: select_target_role, big_flag: true);
        }
        else
        {
            change_soldiers_to_waiting_select_state(-1, target_role: select_target_role, big_flag: true);
        }

        is_confirmed = !need_confirm;
        select_confirm_btn.SetActive(false);
        
        // if (need_confirm)
        // {
        //     select_confirm_btn.SetActive(true);
        // }
        // else
        // {
        //     select_confirm_btn.SetActive(false);
        // }
        var confirm_btn_comp = select_confirm_btn.GetComponent<Button>();
        var confirm_btn_color_comp = confirm_btn_comp.gameObject.GetComponent<Image>();

        while (!is_confirmed || need_select_num > 0)
        {
            yield return new WaitForSeconds(0.2f);

            // BdPackage.BdUtils.log($"--- is_confirmed: {is_confirmed}, need_select_num: [{need_select_num}], cancel_select: [{cancel_select}], end_select: [{end_select}]");

            if (need_select_num == 0 && need_confirm)
            {
                select_confirm_btn.SetActive(true);
                confirm_btn_comp.enabled = true;
                confirm_btn_color_comp.color = Color.green;
            }
            else
            {
                // select_confirm_btn.SetActive(false);
                confirm_btn_comp.enabled = false;
                // confirm_btn_color_comp.color = Color.blue;  // 太蓝色了, 换个浅蓝色
                confirm_btn_color_comp.color = new Color(0.5f, 0.5f, 1f, 1f);
            }
            
            if (cancel_select)
            {
                break;
            }
        }
        
        is_waiting_select_state = false;

        float wait_time = need_confirm && !cancel_select ? 0.33f : 0.15f;
        yield return new WaitForSecondsRealtime(wait_time);

        change_soldiers_to_waiting_select_state(target_i: -1, target_role: select_target_role, big_flag: false);

        if (cancel_select)
        {
            // 这里触发取消事件
            BdPackage.BdUtils.log($"--- 触发取消事件, old_belong_to: {old_belong_to}, old_is_in_hand: {old_is_in_hand}, old_ordering: {old_ordering}");
            move_card_to_selected_place(card_comp, target_role: old_belong_to, is_in_hand: old_is_in_hand, ordering: old_ordering);
            // move_card_to_selected_place(card_comp);
        }
        else if (need_select_num == 0)
        {
            // 这里触发选中事件
            card_comp.OnUse();
        }
        
        is_waiting_select_state = false;
    }

    public void change_soldiers_to_waiting_select_state(List<int> target_ids,
        RoleTypeEnum target_role = RoleTypeEnum.player, bool big_flag = true)
    {

        for (int i = 0; i < target_ids.Count; i++)
        {
            change_soldiers_to_waiting_select_state(i, target_role: target_role, big_flag: big_flag, exclude_mode: false);
        }
    }
    public void change_soldiers_to_waiting_select_state(int target_i=-1, RoleTypeEnum target_role = RoleTypeEnum.player, bool big_flag = true, bool exclude_mode = true)
    {
        BdPackage.BdUtils.assert(target_role == RoleTypeEnum.player || target_role == RoleTypeEnum.store_owner);
        
        mask_canvas.SetActive(big_flag);
        
        var (y, max_length, card_ls) = get_info_by_card_obj(target_role, is_in_hand: false);
        for (var i = 0; i < card_ls.Count; i++)
        {
            if (i == target_i && exclude_mode)
            {
                continue;
            }
            
            var player_soldier_i = card_ls[i];
            var card_comp_i = player_soldier_i.GetComponent<CardController>();
            BdPackage.BdUtils.assert(card_comp_i != null, 
                $"--- i[{i}] --- CardController component from obj[{player_soldier_i.name}] is null?");

            if (big_flag)
            {
                card_comp_i.change_to_waiting_select_state();
            }
            else
            {
                card_comp_i.change_to_waiting_select_state(cancel: true);
            }
            
            if (i == target_i && !exclude_mode)
            {
                return;
            }
        }
    }

    RectBounds rect_bounds => ScreenPlaceManager.instance.rect_bounds;
    
    private (float, int, List<GameObject>) get_info_by_card_obj(RoleTypeEnum role_type = RoleTypeEnum.player, bool is_in_hand = false)
    {
        float y;
        if (!is_in_hand)
        {
            y = role_type == RoleTypeEnum.player ? cards_y_down : cards_y_top;
        }
        else
        {
            y = role_type == RoleTypeEnum.player ? rect_bounds.player_hands_place.center.y : rect_bounds.enemy_hands_place.center.y;
        }
        
        // BdPackage.BdUtils.log($"--- get_info_by_card_obj --- y: {y}, is_in_hand: {is_in_hand}, role_type: {role_type}");
        
        int max_length = max_len_store;
        switch (role_type)
        {
            case RoleTypeEnum.player:
                max_length = is_in_hand? max_len_cards_in_hand: max_len_player;
                break;
            case RoleTypeEnum.enemy:
                max_length = is_in_hand? max_len_cards_in_hand: max_len_enemy;
                break;
        }

        List<GameObject> card_ls = role_cards_dc[role_type][is_in_hand];
        return (y, max_length, card_ls);
    }
    
    
    public int get_ordering_of_position(Vector3 position, RoleTypeEnum role_type = RoleTypeEnum.player, bool is_in_hand = false)
    {
        // 检查指定position位于card_ls的哪个ordering位置
        var (y, max_length, card_ls) = get_info_by_card_obj(role_type, is_in_hand);

        if (is_full_for_selected_place(max_length, card_ls))
        {
            BdPackage.BdUtils.log($"--- is_full_for_selected_place, max_length: {max_length}, card_ls.Count: {card_ls.Count}");
            return -1;
        }
        
        // position_range
        
        var center_ls = get_center_ls(card_ls.Count + 1);
        center_ls.Sort();

        if (center_ls.Count == 0)
            return 0;
        // BdPackage.BdUtils.log("--- center_ls:", center_ls);

        float x = position.x;
        
        // BdPackage.BdUtils.log("--- y: ", y);
        // BdPackage.BdUtils.log("--- center_ls: ", center_ls, ", x:", x);

        // 如果 x 小于第一个点，返回0
        if (x < center_ls[0])
        {
            return 0;
        }
        
        // 遍历中心点列表
        for (int i = 0; i < center_ls.Count - 1; i++)
        {
            if (x >= center_ls[i] && x < center_ls[i + 1])
            {
                return i + 1; // 返回区间编号，从1开始
            }
        }
        
        return center_ls.Count;
    }

    public bool is_full_for_selected_place(int max_length, List<GameObject> card_ls)
    {
        if (card_ls.Count + 1 > max_length)
        {
            return true;
        }

        return false;
    }
    
    public bool is_full_for_selected_place(RoleTypeEnum role_type = RoleTypeEnum.None, bool is_in_hand = false)
    {
        var (y, max_length, card_ls) = get_info_by_card_obj(role_type, is_in_hand);
        return is_full_for_selected_place(max_length, card_ls);
    }
    
    public bool is_ls_contains_card(GameObject card_obj, RoleTypeEnum target_role = RoleTypeEnum.None, bool is_in_hand = false)
    {
        return false;
    }
    
    public bool move_card_to_selected_place(GameObject card_obj, int ordering, RoleTypeEnum target_role = RoleTypeEnum.None, bool is_in_hand = false, bool fail_to_recycle = false)
    {
        BdPackage.BdUtils.assert(target_role != RoleTypeEnum.None, "role_type cannot be RoleTypeEnum.None!");
        
        var soldier = card_obj.GetComponent<CardController>();

        var old_belong_to = soldier.parameter.belong_to;
        var old_is_in_hand = soldier.parameter.is_in_hand;
        var old_ordering = soldier.parameter.ordering;
        
        // if (old_belong_to == target_role && old_is_in_hand == is_in_hand && old_ordering == ordering)
        // {
        //     return true;
        // }
        
        var (y, max_length, card_ls) = get_info_by_card_obj(target_role, is_in_hand);
        
        // BdPackage.BdUtils.log( "~~~ y:", y, ", max_length:", max_length, ", card_ls.Count:", card_ls.Count,
        //     ", target_role:", target_role, ", ordering:", ordering, ", is_in_hand:", is_in_hand);
        
        ordering = Mathf.Clamp(ordering, 0, card_ls.Count);
        if (card_ls.Count + 1 > max_length)
        {
            EventManager.instance.FireEvent(GameEventTypeEnum.OnTooMoreSoldier.ToString(), "--- from add_player_soldier");

            BdPackage.BdUtils.log($"*** card_ls.Count is out of range max_length[{max_length}]");

            if (fail_to_recycle)
            {
                recycle_one_card(card_obj);
            }

            return false;
        }

        BdPackage.BdUtils.assert(soldier != null, "CardController Component is null?");
        BdPackage.BdUtils.assert(soldier.parameter != null, "soldier.parameter is null?");
        
        soldier.parameter.ordering = ordering;
        soldier.parameter.soldier_obj = soldier.gameObject;
        var down_obj = BdPackage.BdTools.get_game_object_by_path("cards_y_down", store_place);
        soldier.transform.SetParent(down_obj.transform);
        
        // set_soldier_ordering_text(soldier.gameObject, ordering);

        // bool is_first_meet = true;
        // bool is_insert_mode = ordering < card_ls.Count;  // 添加soldier的放法分为 [insert: 插入模式, append: 追加模式]
        
        BdPackage.BdUtils.assert(soldier != null, "SoldierComponent is null?");
        card_ls.Insert(ordering, soldier.gameObject);
        BdPackage.BdUtils.assert(card_ls[ordering].GetComponent<CardController>() != null, "*** Component[CardController] is null?");

        soldier.parameter.ordering = ordering;
        soldier.parameter.belong_to = target_role;
        soldier.parameter.is_in_hand = is_in_hand;
        
        card_obj.name = soldier.card_obj_name;

        if (target_role != RoleTypeEnum.store_owner && target_role != RoleTypeEnum.None)
            soldier.is_frozen = false;

        if (old_belong_to != target_role || old_is_in_hand != is_in_hand)
        {
            var (old_y, old_max_length, old_card_ls) = get_info_by_card_obj(old_belong_to, old_is_in_hand);
            // BdPackage.BdUtils.assert(old_card_ls.Contains(card_obj), "旧列表[old_card_ls]不包含卡牌[card_obj]?");
            if (old_card_ls.Contains(card_obj))
            {
                old_card_ls.Remove(card_obj);
                var old_center_ls = get_center_ls(old_card_ls.Count + 1);
                old_center_ls.Sort();
                refresh_place_cards_order(old_card_ls, old_y);
            }
        }

        // --- refresh_place_cards_order
        refresh_place_cards_order(card_ls, y, ordering, soldier);

        return true;
    }

    public void show_animation_of_add_player_soldier(int ordering, List<float> center_ls, float y)
    {
        for (var i = 0; i < player_soldiers.Count; i++)
        {
            var player_soldier_i = player_soldiers[i];
            var player_soldier_comp_i = player_soldier_i.GetComponent<CardController>();

            // Vector3 new_position = change_position_x(player_soldier_i.transform.position, center_ls[i]);
            Vector3 new_position = new Vector3(center_ls[i], y, player_soldier_i.transform.position.z);
            
            if (i < ordering)
            {
                player_soldier_i.transform.DOMove(new_position, 0.2f);
            }
            else if (i == ordering)
            {
                // soldier.transform.position = Vector3.zero;
                // soldier.transform.DOMove(new_position, 0.2f);
            }
            else
            {
                // soldier.parameter.ordering = i;
                player_soldier_i.transform.DOMove(new_position, 0.2f);
                // set_soldier_ordering_text(player_soldier_i, i);
            }
        }
    }
    
    // --- 这几个位置信息, 还是自动获取自适应屏幕ui的位置比较好
    [HideInInspector] private float cards_y_top = 3f;
    [HideInInspector] private float cards_y_down = -3f;
    [HideInInspector] [Header("位置范围")] public List<float> position_range;

    public List<float> get_center_ls(int count_of_ls)
    {
        var center_ls = judge_is_odd(count_of_ls) ? odd_center_positions : even_center_positions;
        center_ls = center_ls.Take(count_of_ls).ToList();
        return center_ls;
    }
    public float get_position_x_of_card_center(int ordering, int count_of_ls)
    {
        var center_ls = get_center_ls(count_of_ls);
        BdPackage.BdUtils.assert(ordering < center_ls.Count, $"ordering[{ordering}] out of range[{center_ls.Count}]!");;
        float x = center_ls[ordering];
        return x;
    }

    private const int MAX_LENGTH = 10;
    [HideInInspector] public List<float> odd_center_positions;
    [HideInInspector] public List<float> even_center_positions;

    public bool judge_is_odd(int x)
    {
        return x % 2 == 1;
    }

    private List<float> _get_positions(int card_num)
    {
        bool is_odd = judge_is_odd(card_num);
        float center = position_range[0] + (float)(position_range[1] - position_range[0]) / 2;

        List<float> pos_cards = new List<float>();
        
        int i = 0;
        float offset = 0.5f;
        
        if (is_odd)
        {
            offset = 1f;
            pos_cards.Add(center);
        }
        // else
        // {
        //     i = -1;
        // }
        
        float center_interval = card_spacing + card_width;
        while (pos_cards.Count < card_num)
        {
            float left_center = center - (offset + i) * center_interval;
            float right_center = center + (offset + i) * center_interval;
            
            pos_cards.Add(left_center);
            pos_cards.Add(right_center);
            // if (left_center != right_center)
            //     pos_cards.Add(right_center);
            
            i++;
        }
        return pos_cards;
    }

    private void get_positions()
    {
        if (judge_is_odd(MAX_LENGTH))
        {
            odd_center_positions = _get_positions(MAX_LENGTH);
            even_center_positions = _get_positions(MAX_LENGTH + 1);
        }
        else
        {
            odd_center_positions = _get_positions(MAX_LENGTH + 1);
            even_center_positions = _get_positions(MAX_LENGTH);
        }
    }
    
    public void show_game_init_animation()
    {
        // game_animator.Play("GameInit");
    }
    
    public void show_store_place()
    {
        store_place.SetActive(true);
        battle_place.SetActive(false);
    }
    
    public void show_battle_place()
    {
        store_place.SetActive(false);
        battle_place.SetActive(true);
    }

    bool[] boolValues = new bool[] { true, false };

    void init_role_cards_dc()
    {
        role_cards_dc = new Dictionary<RoleTypeEnum, Dictionary<bool, List<GameObject>>>();
        
        foreach (RoleTypeEnum eventType in Enum.GetValues(typeof(RoleTypeEnum)))
        {
            var dc = new Dictionary<bool, List<GameObject>>();
            foreach (bool value in boolValues)
            {
                var ls = new List<GameObject>();
                dc.Add(value, ls);
            }
            role_cards_dc.Add(eventType, dc);
        }
    }

    void get_card_size()
    {
        // get height and width of card_prefab
        // GameObject cardInstance = Instantiate(card_prefab);
        GameObject cardInstance = ObjectPool.instance.GetObj(card_obj_name, card_prefab);
        cardInstance.SetActive(false);
        // Renderer card_renderer = cardInstance.GetComponent<Renderer>();
        GameObject card_obj = BdTools.get_game_object_by_path("card", parent: cardInstance);
        Renderer card_renderer = BdPackage.BdTools.get_component_in_obj_self_or_children<Renderer>(card_obj);
        BdPackage.BdUtils.assert(card_renderer);
        
        Vector3 size = card_renderer.bounds.size;

        card_height = size.y;
        card_width = size.x;
        // card_spacing = Mathf.CeilToInt(size.x / 2);
        
        if (card_spacing == _default_card_spacing)
        {
            card_spacing = size.x / 2;
        }
        Debug.Log($"card_prefab Size (Renderer), card_height: {card_height}, card_width: {card_width}");
        // Destroy(cardInstance);
        
        ObjectPool.instance.RecycleObj(cardInstance);
    }

    private IEnumerator init_values()
    {
        if (is_ready)
            yield break;

        while (!ScreenPlaceManager.instance.is_ready)
        {
            yield return null;
        }
        
        while (!MyPointsManager.instance.is_ready)
        {
            yield return null;
        }
        
        float interval = 0.01f;
        
        yield return new WaitForSeconds(interval);
        get_card_size();
        
        position_range = new List<float>();

        var bound_up = ScreenPlaceManager.instance.soldier_place_info_ls[0];
        
        cards_y_top = ScreenPlaceManager.instance.center_of_soldier_top.y;
        cards_y_down = ScreenPlaceManager.instance.center_of_soldier_down.y;
        
        var  (width, _, center_top) = ScreenPlaceManager.instance.get_wh_and_center_of_bound(bound_up);
        position_range.Add(center_top.x - width);
        position_range.Add(center_top.x + width);
            
        yield return new WaitForSeconds(interval);
        init_role_cards_dc();
        
        yield return new WaitForSeconds(interval);
        get_positions();
        
        is_ready = true;
    }

    public void btn_log_table()
    {
        TableUtils.show_data_table(card_dt);
    }
    
    public void btn_load_table_coroutine()
    {
        TableUtils.show_data_table(card_dt);
    }
    
    void Start()
    {
        DG.Tweening.DOTween.logBehaviour = DG.Tweening.LogBehaviour.Verbose;
        
        // get_positions();
        StartCoroutine(init_values());
        // init_role_cards_dc();
        mask_canvas.SetActive(false);
        
        var eventData = new Dictionary<string, object>()
        {
            { "a", 123 },
            { "b", "bbb" },
            { "c", "ccc" },
        };
        EventManager.instance.add_event(
            eventType: GameEventTypeEnum.OnTooMoreSoldier.ToString(), eventData: eventData, event_instance: OnTooMoreSoldier, removeWhenRunOnce: false);
        
        // EventManager.instance.add_event(
        //     eventType: GameEventTypeEnum.OnManualRefreshStore.ToString(), eventData: eventData, event_instance: on_manual_refresh_store, removeWhenRunOnce: false);
        //
        // EventManager.instance.add_event(eventType: GameEventTypeEnum.OnManualRefreshStore.ToString(), eventData: eventData, removeWhenRunOnce: false, event_callback:
        //     () =>
        //     {
        //         BdPackage.BdUtils.log("=== OnManualRefreshStore event_callback 111", eventData);
        //     });
    }
    
    public void on_manual_refresh_store(object sender, EventArgs args)
    {
        var (event_obj, event_data) =  EventManager.instance.get_event_obj_and_data(sender);

        BdPackage.BdUtils.log("=== on_manual_refresh_store --- ", sender, " --- event_obj.EventData:", event_obj.EventData);
    }

    public void OnTooMoreSoldier(object sender, EventArgs args)
    {
        var (event_obj, event_data) =  EventManager.instance.get_event_obj_and_data(sender);

        BdPackage.BdUtils.log("=== OnTooMoreSoldier --- ", sender, " --- event_obj.EventData:", event_obj.EventData);
    }

    public string get_card_obj_name(RoleTypeEnum role_type = RoleTypeEnum.None, bool is_in_hand = false)
    {
        var str_is_in_hand = is_in_hand ? 1 : 0;
        // var objName = role_type == RoleTypeEnum.None ? card_obj_name: $"{card_obj_name}__{role_type}__{str_is_in_hand}";
        var objName = $"{card_obj_name}__{role_type}__{str_is_in_hand}";
        return objName;
    }

    public string get_card_obj_name(GameObject card_obj)
    {
        var card_comp = card_obj.GetComponent<CardController>();
        return card_comp.card_obj_name;
    }
    
    public GameObject create_card_obj(CardParameter cardParameter = null, object init_position = null, RoleTypeEnum role_type = RoleTypeEnum.None, bool is_in_hand = false)
    {
        // var objName = cardParameter == null ? card_obj_name : $"card_{cardParameter.card_data.id}";
        // var card_obj = ObjectPool.instance.GetObj(objName, prefab: card_prefab, position: init_position);
        // var prefab_path = "Prefabs/card";
        // var card_obj = ObjectPool.instance.GetObj(card_obj_name, prefab_path, position: init_position);
        
        var obj_name = get_card_obj_name(role_type, is_in_hand);
        // BdPackage.BdUtils.log("create_card_obj --- ", obj_name, role_type, is_in_hand);

        var card_obj = ObjectPool.instance.GetObj(obj_name, prefab: card_prefab, position: init_position);

        // var card_obj = Instantiate(card_prefab);
        card_obj.name = obj_name;
        if (init_position != null)
            card_obj.transform.position = (Vector3)init_position;
        
        var card_comp = card_obj.GetComponent<CardController>();
        if (cardParameter != null)
        {
            if (card_comp.parameter != null && card_comp.parameter.card_data != null)
                card_comp.prepare_recycle();

            card_comp.parameter = cardParameter;

            BdPackage.BdUtils.assert(card_comp.parameter.card_data);
            BdPackage.BdUtils.assert(card_comp.parameter.card_data.OnUse);
        }
        else
        {
            card_comp.parameter = new CardParameter();
            card_comp.prepare_recycle();
            card_comp.parameter.card_data.clear_effect_callbacks();
            card_comp.parameter.card_data = get_card_data();
        }

        BdPackage.BdUtils.assert(card_comp, $"card[{card_obj_name}]'s card_comp is null");
        BdPackage.BdUtils.assert(card_comp.parameter);
        BdPackage.BdUtils.assert(card_comp.parameter.card_data);

        card_comp.parameter.soldier_obj = card_obj.gameObject;

        card_comp.parameter.card_uid = card_uid;
        
        card_comp._recycle_obj_name = obj_name;
        card_obj.name = card_comp.card_obj_name;
        
        card_uid++;
        
        card_obj.SetActive(true);

        card_comp.is_frozen = false;
        
        card_comp.update_drag_card_comp_info();

        // card_comp.init_card_ui_obj(card_comp.parameter);
        card_comp.init_card_ui_obj();
        
        card_comp.btn_update_ui_info();
        return card_obj;
    }

    public void use_card(GameObject card)
    {
        var card_comp = card.GetComponent<CardController>();
        card_comp.OnUse();
    }

    public void recycle_one_card(CardController card_comp)
    {
        recycle_one_card(card_comp.gameObject);
    }
    
    public void recycle_one_card(GameObject card)
    {
        var card_comp = card.GetComponent<CardController>();
        card_comp.prepare_recycle();
        var buff_handle = card.GetComponent<BuffHandle>();
        buff_handle.clear_listener_in_event_ls_dc();
        // if (buff_handle)
        // {
        //     buff_handle.clear_listener_in_event_ls_dc();
        //     buff_handle.buffList.Clear();
        // }
        card.name = card_comp._recycle_obj_name;
        ObjectPool.instance.RecycleObj(card);
    }

    public void clear_cards_in_ls(List<GameObject> card_ls, bool clear = true)
    {
        foreach (var card in card_ls)
        {
            recycle_one_card(card);
        }
        if (clear)
            card_ls.Clear();
    }
    
    public void clear_all_cards_in_place(bool include_hands = false)
    {
        // 清除场上所有卡牌
        clear_cards_in_ls(player_soldiers);
        clear_cards_in_ls(enemy_soldiers);
        clear_cards_in_ls(store_soldiers);
        if (include_hands)
        {
            clear_cards_in_ls(enemy_hands);
            clear_cards_in_ls(player_hands);
        }
    }

    public RoleTypeEnum test_role_type = RoleTypeEnum.store_owner;
    
    [Header("卡牌牌组位置")]
    public Vector3 card_deck_position = new Vector3(4, 0, 0);
    
    public bool debug = false;

    public CardData get_card_data(string script_object_path = "ScriptObjects/cards/CardData")
    {
        return new CardData();
        // var card_data = Resources.Load<CardData>(script_object_path);
        // BdPackage.BdUtils.assert(card_data);
        // return card_data;
    }

    Vector3 store_init_pos
    {
        get
        {
            return new Vector3(0, cards_y_top, 0);
        }
    }

    public void clear_store_cards(bool clear = true)
    {
        clear_cards_in_ls(store_soldiers, clear: clear);
    }
    public void hide_store_cards()
    {
        clear_cards_in_ls(store_soldiers, clear: false);
    }

    public void btn_refresh_store_cards()
    {
        // --- 这里应该判断下金币够不够
        if (BaseInfoManager.instance.current_coins < BaseInfoManager.instance.cost_of_refresh_store)
        {
            BdTools.show_message_box(content: "btn_refresh_store_cards 金币不足", parent_trans: BaseInfoManager.instance.message_parent_canvas);
            return;
        }
        else
        {
            // BdTools.show_message_box(content: "btn_refresh_store_cards 刷新!", parent_trans: BaseInfoManager.instance.message_parent_canvas);
            BaseInfoManager.instance.current_coins -= BaseInfoManager.instance.cost_of_refresh_store;
        }
        
        StatisticManager.instance.add_statistic_value(StatisticTypeEnum.manual_refresh_times);
        EventManager.instance.FireEvent(GameEventTypeEnum.OnManualRefreshStore.ToString());
        
        refresh_store_cards();
    }
    
    public void refresh_store_cards(bool refresh = true)
    {
        if (refresh)
        {
            clear_cards_in_ls(store_soldiers);

            for (var i = 0; i < max_len_store; i++)
            {
                btn_add_card_to_store();
            }
        }
        else
        {
            foreach (var card_i in store_soldiers)
            {
                card_i.SetActive(true);
            }
        }
        EventManager.instance.FireEvent(GameEventTypeEnum.OnRefreshStore.ToString());
        StatisticManager.instance.add_statistic_value(StatisticTypeEnum.total_refresh_times);
    }

    public void clear_enemy_cards(bool clear = true)
    {
        clear_cards_in_ls(enemy_soldiers, clear: clear);
    }
    
    public void hide_enemy_cards()
    {
        clear_cards_in_ls(enemy_soldiers, clear: true);
    }

    public void load_enemy_hero()
    {
        
        var obj = GameController.instance.core_load_card_obj_by_id(3, role_type: RoleTypeEnum.None, is_in_hand: false);
        MyPointsManager.instance.test_trans__enemy = obj.transform;
        MyPointsManager.instance.test_trans__enemy.DOMove(MyPointsManager.instance.enemy_word_pos, 3f);

    }
    
    public void refresh_enemy_cards(bool refresh = true)
    {
        if (refresh)
        {
            clear_cards_in_ls(enemy_soldiers);
 
            for (var i = 0; i < max_len_enemy; i++)
            {
                // btn_add_card_to_enemy(i + 1);
                int card_id = BdPackage.BdUtils.get_random_number(1, max_len_enemy + 1);
                btn_add_card_to_enemy(card_id);
            }
        }
        else
        {
            foreach (var card_i in enemy_soldiers)
            {
                card_i.SetActive(true);
            }
        }
        // EventManager.instance.FireEvent(GameEventTypeEnum.StartBattle.ToString());
        // StatisticManager.instance.add_statistic_value(StatisticTypeEnum.total_refresh_times);
    }

    private DataTable card_dt => BaseInfoManager.instance.card_dt;
    
    private int current_card_id = 0;
    
    public void btn_test_animation_event_system()
    {
        BdPackage.BdUtils.log("--- on btn_test_animation_event_system");
        
        // EventManager.instance.has_event()  // --- 这里应该用event_name来避免重复
        for (var i = 0; i < 3; i++)
        {
            var event_i = EventManager.instance.add_animation_event(eventName: $"AnimationEvent_{i}", removeWhenRunOnce: false);
            event_i.event_callback = (sender, args) =>
            {
                BdPackage.BdUtils.log("--- ~~~ on btn_test_animation_event_system event_callback");
                
                float t = 2f; // [延迟/等待/休眠/timeout]t秒后执行
                DOTween.To(() => t, (x) => t = x, 0, t).OnComplete(
                    () =>
                    {
                        BdPackage.BdUtils.log($"--- ~~~ on btn_test_animation_event_system event_callback 222 --- {event_i.EventName}");
                        
                        level_up_effect.SetActive(false);
                        level_up_effect.SetActive(true);
                        
                        event_i.finished = true;
                    }
                );

                return "";
            };
        
            event_i.max_running_time = 3f;
            event_i.min_running_time = 1f;
        }
    }

    public List<GameObject> get_alive_soldiers(List<GameObject> soldier_ls)
    {
        var alive_soldiers = soldier_ls.Where(card => card.activeInHierarchy && card.GetComponent<CardController>().curr_hp > 0).ToList();
        return alive_soldiers;
    }
    public int get_alive_soldiers_total_stars(List<GameObject> soldier_ls)
    {
        if (soldier_ls == null)
            return 0;
        
        int total_stars = 0;
        foreach (var soldier_obj_i in soldier_ls)
        {
            var soldier_comp_i = soldier_obj_i.GetComponent<CardController>();
            total_stars += soldier_comp_i.parameter.card_data.star_level;
        }
        return total_stars;
    }
    
    public GameObject get_alive_soldier_by_random_choose(List<GameObject> soldier_ls)
    {
        var alive_soldiers = get_alive_soldiers(soldier_ls);
        if (alive_soldiers.Count <= 0)
            return null;
        int random_index = BdUtils.get_random_number(0, alive_soldiers.Count);
        var soldier_i = alive_soldiers[random_index];
        return soldier_i;
    }
    
    public GameObject get_first_alive_soldier(List<GameObject> soldier_ls)
    {
        var soldier_i = soldier_ls.Find(card => card.activeInHierarchy && card.GetComponent<CardController>().curr_hp > 0);
        return soldier_i;
    }

    public void reset_soldier_attack_times(List<GameObject> soldier_ls)
    {
        foreach (var soldier_obj_i in soldier_ls)
        {
            var card_comp = soldier_obj_i.GetComponent<CardController>();
            card_comp.attack_times = 0;
        }
    }
    
    public GameObject get_next_attack_soldier(List<GameObject> soldier_ls)
    {
        var alive_soldiers = get_alive_soldiers(soldier_ls);
        if (alive_soldiers.Count <= 0)
            return null;
        var sorted_soldiers = alive_soldiers
            .OrderBy(go => go.GetComponent<CardController>().attack_times)
            .ThenBy(go => go.GetComponent<CardController>().parameter.ordering)
            .ToList();

        var names = new List<string>();
        foreach (var go in sorted_soldiers)
        {
            names.Add(go.GetComponent<CardController>().card_obj_name);
        }
        // BdPackage.BdUtils.log("--- sorted_soldiers names:", names);

        var soldier_i = sorted_soldiers[0];
        return soldier_i;
    }
    
    public GameObject get_last_alive_soldier(List<GameObject> soldier_ls)
    {
        var soldier_i = soldier_ls.LastOrDefault(card => card.activeInHierarchy && card.GetComponent<CardController>().curr_hp > 0);
        return soldier_i;
    }

    [HideInInspector] public bool is_fighting = false;
    [HideInInspector] public GameEndingTypeEnum fight_ending = GameEndingTypeEnum.None;
    [HideInInspector] public int total_remain_soldier_stars = 0;

    public void start_fight()
    {
        if (is_fighting)
            return;
        
        StartCoroutine(_start_fight());
    }

    public bool debug_shield = false;

    IEnumerator _start_fight()
    {
        fight_ending = GameEndingTypeEnum.None;
        is_fighting = true;

        // BdPackage.BdUtils.log("--- start fight 1 ---");
        bool is_first_strike = true;
            
        reset_soldier_attack_times(store_soldiers);
        reset_soldier_attack_times(enemy_soldiers);
        reset_soldier_attack_times(player_soldiers);

        while (true)
        {
            yield return new WaitForSeconds(0.15f);

            EventManager.instance.add_blocking_event();

            List<GameObject> receiver_objs;
            List<GameObject> attacker_objs;
            
            var target_soldier = debug_shield ? store_soldiers : enemy_soldiers;
            
            if (is_first_strike)
            {
                receiver_objs = target_soldier;
                attacker_objs = player_soldiers;
            }
            else
            {
                receiver_objs = player_soldiers;
                attacker_objs = target_soldier;
            }
            
            var receiver_obj_0 = get_alive_soldier_by_random_choose(receiver_objs);
            if (receiver_obj_0 == null)
                break;

            // var attacker_obj_0 = get_first_alive_soldier(attacker_objs);
            var attacker_obj_0 = get_next_attack_soldier(attacker_objs);
            if (attacker_obj_0 == null)
                break;
        
            var attacker_comp_0 = attacker_obj_0.GetComponent<CardController>(); 
            attacker_comp_0.attack_target_obj(receiver_obj_0);

            EventManager.instance.add_blocking_event();
            
            yield return new WaitForSeconds(0.15f);
            
            is_first_strike = !is_first_strike;
        }

        // BdPackage.BdUtils.log("--- start fight 2 ---");

        var alive_enemy_soldiers = get_alive_soldiers(enemy_soldiers);
        var alive_player_soldiers = get_alive_soldiers(player_soldiers);

        List<GameObject> winner_soldiers = null;
        
        CardController winner_comp = null;
        CardController loser_comp = null;
        
        if (alive_player_soldiers.Count == alive_enemy_soldiers.Count)
        {
            fight_ending = GameEndingTypeEnum.Draw;
        }
        else if (alive_player_soldiers.Count > alive_enemy_soldiers.Count)
        {
            fight_ending = GameEndingTypeEnum.Win;
            winner_soldiers = alive_player_soldiers;
            winner_comp = MyPointsManager.instance.test_trans__player.GetComponent<CardController>();
            loser_comp = MyPointsManager.instance.test_trans__enemy.GetComponent<CardController>();
        }
        else
        {
            fight_ending = GameEndingTypeEnum.Lose;
            winner_soldiers = alive_enemy_soldiers;
            winner_comp = MyPointsManager.instance.test_trans__enemy.GetComponent<CardController>();
            loser_comp = MyPointsManager.instance.test_trans__player.GetComponent<CardController>();
        }
        total_remain_soldier_stars = get_alive_soldiers_total_stars(winner_soldiers);

        // BdPackage.BdUtils.log("--- start fight 3 ---");

        // --- 角色伤害结算
        // if (fight_ending != GameEndingTypeEnum.Draw)
        // {
        //     // BdPackage.BdUtils.log($"=== fight_ending: {fight_ending}, total_remain_soldier_stars: {total_remain_soldier_stars}, winner_comp: {winner_comp}, loser_comp: {loser_comp}");
        //     // BdPackage.BdUtils.log($"=== enemy: {MyPointsManager.instance.enemy.gameObject.name}, player: {MyPointsManager.instance.player.gameObject.name}");
        //     yield return new WaitForSeconds(0.2f);
        //
        //     EventManager.instance.add_blocking_event();
        //
        //     // BdPackage.BdUtils.assert(winner_comp != null);
        //     // BdPackage.BdUtils.assert(loser_comp != null);
        //     
        //     BdPackage.BdUtils.assert(winner_comp?.gameObject.activeInHierarchy, "winner已死亡?");
        //     BdPackage.BdUtils.assert(loser_comp?.gameObject.activeInHierarchy, "loser已死亡?");
        //
        //     winner_comp?.set_current_atk_value(total_remain_soldier_stars);
        //     loser_comp?.set_current_atk_value(0);
        //
        //     winner_comp?.attack_target_obj(loser_comp?.gameObject);
        //
        //     EventManager.instance.add_blocking_event();
        //     
        //     yield return new WaitForSeconds(0.2f);
        // }
        
        // --- 这里需要死亡动画
        
        is_fighting = false;
    }

    private void OnGUI()
    {
        if (!is_ready)
            return;
        
        if (!debug)
            return;

        if (GUILayout.Button("btn_save_current_soldiers_state"))
        {
            SoldierStateManager.instance.btn_save_current_soldiers_state();
        }
        
        if (GUILayout.Button("btn_restore_soldiers_state"))
        {
            SoldierStateManager.instance.btn_restore_soldiers_state();
        }

        if (GUILayout.Button("taunt相关"))
        {
            var card_comp = store_soldiers[0].GetComponent<CardController>();
            card_comp.is_active_for_taunt = !card_comp.is_active_for_taunt;
        }
        
        // if (GUILayout.Button("打印[player_soldiers]"))
        // {
        //     foreach (var card_obj in SoldierStateManager.instance.temp_player_soldiers)
        //     {
        //         var card_comp = card_obj.GetComponent<CardController>();
        //         var buff_comp = card_obj.GetComponent<BuffHandle>();
        //         BdPackage.BdUtils.assert(card_comp != null, "card_comp 不能为空!");
        //         BdPackage.BdUtils.assert(buff_comp != null, "buff_comp 不能为空!");
        //         BdPackage.BdUtils.assert(card_comp.parameter != null, "card_comp.parameter 不能为空!");
        //         BdPackage.BdUtils.assert(card_comp.card_data != null, "card_comp.card_data 不能为空!");
        //         BdPackage.BdUtils.log($"buffs.Count: {buff_comp.buffList.Count}" ,"--- card_name:", card_comp.card_data.card_name);
        //     }
        // }
    
        if (GUILayout.Button("打印[OnRefreshStore]的监听事件"))
        {

            string event_type = GameEventTypeEnum.OnRefreshStore.ToString();
            EventManager.instance.FireEvent(event_type);
            var events = EventManager.instance.event_dc[event_type].Events;
            // var events = EventManager.instance.event_dc[event_type];
            foreach (var event_i in events)
            {
                BdPackage.BdUtils.log($"*** OnRefreshStore.event_i: {event_i.ToString()}");
            }
        }
        
        if (GUILayout.Button("转为init状态"))
        {
            GameStateManager.instance.TransitionState(GameStateEnum.Init);
        }
        
        if (GUILayout.Button("清除场上所有卡牌"))
        {
            clear_all_cards_in_place();
        }

        if (GUILayout.Button("start_fight"))
        {
            start_fight();
        }

        if (GUILayout.Button("加速"))
        {
            if (Time.timeScale == 2f)
                Time.timeScale = 1f;
            else
            {
                Time.timeScale = 2f;
            }
        }
        
        if (GUILayout.Button("加载卡牌测试"))
        {
            int card_id = current_card_id;
            current_card_id++;

            bool fail_to_recycle = true;

            GameObject card_obj;
            for (var i = 0; i < 3; i++)
            {
                // card_obj = core_load_card_obj_by_id(card_id + 1);
                card_obj = core_load_card_obj_by_id(1);
                move_card_to_selected_place(card_obj, ordering: 999, target_role: RoleTypeEnum.player, is_in_hand: true, fail_to_recycle: fail_to_recycle);
            }
            
            // card_obj = core_load_card_obj_by_id(2);  // 篮球
            // move_card_to_selected_place(card_obj, ordering: 999, target_role: RoleTypeEnum.player, is_in_hand: true, fail_to_recycle: fail_to_recycle);
            //
            // card_obj = core_load_card_obj_by_id(4);  // lihua
            // move_card_to_selected_place(card_obj, ordering: 999, target_role: RoleTypeEnum.player, is_in_hand: true, fail_to_recycle: fail_to_recycle);
        }
    }

    public const int DELTA_EFFECT_ID = 50000;
    public const int DELTA_BUFF_ID = 10000;
    private int TABLE_MAX_ID = 4;

    public int get_effect_id(int card_id)
    {
        return DELTA_EFFECT_ID + card_id;

    }
    public int get_buff_id(int card_id)
    {
        return DELTA_BUFF_ID + card_id;
    }

    public int get_effect_buff_id(int card_id)
    {
        return get_effect_id(card_id);
    }
    
    public GameObject core_load_card_obj_by_id(int card_id, RoleTypeEnum role_type = RoleTypeEnum.None, bool is_in_hand = false)
    {
        if (card_id > TABLE_MAX_ID)
            card_id = card_id % TABLE_MAX_ID + 1;
        var card_row = TableUtils.get(card_dt, pk: card_id);
        
        var card_dc = TableUtils.conv_row_to_dc(card_row);

        CardData cardData = new CardData();
        
        cardData.id = BdPackage.BdUtils.conv_to_int(card_dc["ID"]);
        var card_name = BdPackage.BdUtils.conv_to_string(card_dc["card_name"]);
        cardData.card_name = card_name;
        cardData.description = BdPackage.BdUtils.conv_to_string(card_dc["description"]);
        
        cardData.attack = BdPackage.BdUtils.conv_to_int(card_dc["attack"]);
        cardData.hp = BdPackage.BdUtils.conv_to_int(card_dc["hp"]);
        cardData.icon_path = BdPackage.BdUtils.conv_to_string(card_dc["icon_path"]);

        cardData.use_target_num = BdPackage.BdUtils.conv_to_int(card_dc["use_target_num"]);
        cardData.star_level = BdPackage.BdUtils.conv_to_int(card_dc["star_level"]);
        cardData.effect_type_name = BdPackage.BdUtils.conv_to_string(card_dc["effect_type_name"]);
        
        cardData.cost_value = BdPackage.BdUtils.conv_to_int(card_dc["cost_value"]);
        var cost_type_string = BdPackage.BdUtils.conv_to_string(card_dc["cost_type"]);
        BdPackage.BdUtils.assert(Enum.TryParse(cost_type_string, out cardData.cost_type),
            $"cost_type_string[{cost_type_string}] is not a valid CostTypeEnum");;
        
        var card_type_string = BdPackage.BdUtils.conv_to_string(card_dc["card_type"]);
        BdPackage.BdUtils.assert(Enum.TryParse(card_type_string, out cardData.card_type),
            $"card_type_string[{card_type_string}] is not a valid CardTypeEnum");;

        cardData.name = $"CardData__{cardData.id}";
        
        if (card_name == "ruby")
        {
            // string effect_type_name = nameof(CardEffects.CardEffect_AddShield);
            string effect_type_name = cardData.effect_type_name;
            BdPackage.BdUtils.log("--- effect_type_name:", effect_type_name);

            Dictionary<string, object> dc = new Dictionary<string, object>();

            dc.Add("buff_id", get_buff_id(card_id));
            dc.Add("creator_card_uid", card_uid);
            var new_effect_script_obj = CardEffects.CardEffectFactory.CreateProduct(effect_type_name, dc);
            cardData.OnAppearInStore = new_effect_script_obj;
            cardData.OnAppearInBattle = new_effect_script_obj;
            cardData.OnUse = new_effect_script_obj;
        }
        else if (card_name == "portrait")
        {
            // BdPackage.BdUtils.log($"~~~~~~ add CardEffect_ManualRefreshListener: {card_id} --- {card_obj_name} --- {cardData.card_name}");
            // var new_effect_script_obj = ScriptableObject.CreateInstance<CardEffects.CardEffect_ManualRefreshListener>();
            var new_effect_script_obj = new CardEffects.CardEffect_ManualRefreshListener();
            new_effect_script_obj.buff_id = get_buff_id(card_id);
            cardData.OnUse = new_effect_script_obj;
        }
        else if (card_name == "lihua")
        {
            string effect_type_name = nameof(CardEffects.CardEffect_AddHpAtkBuff);

            Dictionary<string, object> dc = new Dictionary<string, object>();
            dc.Add("buff_id", get_buff_id(card_id));
            dc.Add("delta_atk", 1);
            dc.Add("delta_hp", 10);
            var new_effect_script_obj = CardEffects.CardEffectFactory.CreateProduct(effect_type_name, dc);
            cardData.OnUse = new_effect_script_obj;
        }
        else if (card_name == "篮球")
        {
            // BdPackage.BdUtils.log($"~~~~~~ add CardEffect_AddHpAtkBuff: {card_id} --- {card_obj_name} --- {cardData.card_name}");
            // var old_effect_script_obj = Resources.Load<CardEffects.CardEffect_AddHpAtkBuff>(old_effect_script_obj_path);
            
            // var new_effect_script_obj = ScriptableObject.CreateInstance<CardEffects.CardEffect_AddHpAtkBuff>();

            string effect_type_name = nameof(CardEffects.CardEffect_AddHpAtkBuff);
            BdPackage.BdUtils.log("--- effect_type_name:", effect_type_name);

            // var new_effect_script_obj = CardEffects.CardEffectFactory.CreateProduct(effect_type_name);

            Dictionary<string, object> dc = new Dictionary<string, object>();
            dc.Add("buff_id", card_id);
            dc.Add("delta_atk", 2);
            dc.Add("delta_hp", 5);
            var new_effect_script_obj = CardEffects.CardEffectFactory.CreateProduct(effect_type_name, dc);
            // new_effect_script_obj.delta_atk = 2;
            // new_effect_script_obj.delta_hp = 1;
            cardData.OnUse = new_effect_script_obj;
        }
        else
        {
            // string old_effect_script_obj_path = "ScriptObjects/cards/CardEffect_CreateSoldier";
            // CardEffects.CardEffect_CreateSoldier old_effect_script_obj = Resources.Load<CardEffects.CardEffect_CreateSoldier>(old_effect_script_obj_path);
            // CardEffects.CardEffect_CreateSoldier new_effect_script_obj = Instantiate(old_effect_script_obj);
            
            CardEffects.CardEffect_CreateSoldier new_effect_script_obj = new CardEffects.CardEffect_CreateSoldier();

            // new_effect_script_obj = (CardEffects.CardEffect_CreateSoldier)Instantiate(old_effect_script_obj);
            new_effect_script_obj.a = 12;
            new_effect_script_obj.b = 23;
            
            cardData.OnUse = new_effect_script_obj;
            // string effectDataPath = $"Assets/Resources/{old_effect_script_obj_path}__{cardData.id}.asset";
        }
        
        // 从资源中加载原始实例
        // CardEffects.CardEffect_CreateSoldier original = AssetDatabase.LoadAssetAtPath<CardEffects.CardEffect_CreateSoldier>(originalPath);

        // CardEffect_CreateSoldier createSoldierEffect = ScriptableObject.CreateInstance<CardEffect_CreateSoldier>();
        // cardData.OnCreateSoldier = new_effect_script_obj;


        // string cardDataPath = $"Assets/Resources/ScriptObjects/cards/{cardData.name}.asset";
        
        // AssetDatabase.CreateAsset(new_effect_script_obj, effectDataPath);
        // // 保存 CardData 实例为资源文件
        // AssetDatabase.CreateAsset(cardData, cardDataPath);
        // // 确保所有资源变更立即保存
        // AssetDatabase.SaveAssets();

        var card_params = new CardParameter();

        // card_params.card_data = get_card_data(script_object_path: cardDataPath);
        
        card_params.card_data = cardData;
        // card_comp.parameter.card_data.clear_effect_callbacks();

        var card_obj = create_card_obj(cardParameter: card_params, role_type: role_type, is_in_hand: is_in_hand);
        return card_obj;
    }

    public void btn_add_card_to_player_place(int card_id = -1)
    {
        if (card_id == -1)
        {
            card_id = current_card_id;
            current_card_id++;
        }

        var card_obj = core_load_card_obj_by_id(card_id + 1, role_type: RoleTypeEnum.player, is_in_hand: false);
        var success_flag = add_one_card_to_store(card_obj, fail_to_recycle: false);
        if (success_flag)
        {
            var card_comp = card_obj.GetComponent<CardController>();
            card_comp.parameter.card_data.OnAppearInStore?.Apply(card_obj);
        }
    }
    public void btn_add_card_to_store(int card_id = -1)
    {
        if (card_id == -1)
        {
            card_id = current_card_id;
            current_card_id++;
        }

        var card_obj = core_load_card_obj_by_id(card_id + 1, role_type: RoleTypeEnum.store_owner, is_in_hand: false);
        var success_flag = add_one_card_to_store(card_obj, fail_to_recycle: false);
        if (success_flag)
        {
            var card_comp = card_obj.GetComponent<CardController>();
            card_comp.parameter.card_data.OnAppearInStore?.Apply(card_obj);
        }
        
    }
    public void btn_add_card_to_enemy(int card_id)
    {
        // BdPackage.BdUtils.log($"--- btn_add_card_to_enemy, card_id: {card_id}");

        var card_obj = core_load_card_obj_by_id(card_id, role_type: RoleTypeEnum.enemy, is_in_hand: false);
        
        move_card_to_selected_place(card_obj, ordering: 999, target_role: RoleTypeEnum.enemy, fail_to_recycle: true);
        
        var card_comp = card_obj.GetComponent<CardController>();
        card_comp.parameter.card_data.OnAppearInBattle?.Apply(card_obj);
    }

    public bool add_one_card_to_store(GameObject card_obj, int ordering = 999, bool fail_to_recycle = false)
    {
        var success_flag = move_card_to_selected_place(card_obj, ordering, target_role: RoleTypeEnum.store_owner, fail_to_recycle: fail_to_recycle);
        return success_flag;
    }

    [HideInInspector] public bool is_ready = false;

    public int x = 1;
    void Update()
    {
        if (!is_ready)
            return;

        if (!debug)
            return;
    }
}
